<?php // $Id: sharpobj_storage.php,v 1.11 2006/07/05 11:45:36 alex Exp $
// Хранилище данных
// !!! Исправить класс формата, для упрощения работы с провайдерами и получения данных из sql-запроса

// Интерфейс класса-хранилища
interface sharpobj_storage_interface
{
	/**
	 * Инициализация объекта форматом	
	 * @param sharpobj_storage_format	$format
	 * @return void
	 */
    // function __construct(sharpobj_storage_format $format, $opt);
	// function addItem();
    /**
     * Вставить запись в базу данных
     *
     * @param sharpobj_data_interface_item $data
     */
    function insert(sharpobj_data_item_data $data);
    /**
     * Обновить запись с $id
     * Если $emptyreplace == true - пустые записи тоже обновляются
     *
     * @param int $id
     * @param sharpobj_data_interface_item $data
     * @param bool $emptyreplace
     * @param sharpobj_data_interface_item $data
     */
    function update(sharpobj_data_item_data $data,$id=null,$emptyreplace=false);
    /**
     * Удалить запись по ее id
     *
     * @param int $id
     * @return bool
     */
    function delete($id);
    /**
     * Получить запись по ее id
     *
     * @param int $id
     * @return bool
     */
    function get($id);
    /**
     * Посчитать количество записей в хранилище
     *
     * @return sharpobj_data_interface_item
     */
    function count();
    // function countByField(string $field,string $data);
    function getListAll($from=null,$limit=null);	


    // function getList(string $field,string $data);
    // function getListByField(string $field,string $data);
    // function setField(string $name_data,string $name_storage,mixed $format);
    // function getField(string $name_data);
    /**
     * Вернуть объект формата
     * @return sharpobj_data_interface_item
     */
    function getObj($datapath=null);

}

interface sharpobj_storage_interface_sql extends sharpobj_storage_interface
{
    function setConnection(&$connect,$readonly=false);
    function &getConnection($readonly=false);
    /**
     * Сделать sql-запрос к базе данных (функция низкого уровня)
     * $type - тип ожидаемого результата запроса
     *    sqlres - не обработанный результат
     *    assocvalue - одна строка, переведенная в ассоциативный массив
     *    rowvalue - одна строка, переведенная в нумерованный массив
     *    onevalue - первая запись первой строки результата
     *    action - возвращает true, если запрос выполнен без ошибок
     *    insert - возвращает id последней вставленной записи
     * $sql - sql-запрос
     *
     * @param string $sql
     * @param string $type
     */
    function sqlquery($sql,$type);
    /**
     * Выбрать список объектов из базы по sql-запросу
     * @param string $sql
     */	
    function sqlqueryList($sql);
    /**
     * Выбрать значение из базы
     * @param string $sql
     */	
    function sqlqueryOneValue($sql);
    /**
     * Выбрать нумерованный массив из базы
     * @param string $sql
     */
    function sqlqueryRowValue($sql);
    /**
     * Выбрать ассоциативный массив из базы
     * @param string $sql
     */	
    function sqlqueryAssocValue($sql);
    /**
     * Выполнить действие в базе данных
     * @param string $sql
     */		
    function sqlqueryAction($sql);
    
    // Перенес из основного класса
	function countUp($id,$field);
	function countDown($id,$field);
}

abstract  class sharpobj_storage_proto_sql implements sharpobj_storage_interface_sql
{
	protected $tbname=null;
	protected $idfield=null;
	protected function tbname()
	{
		return '`'.$this->tbname.'`';
	}
	protected function idfield()
	{
		return '`'.$this->idfield.'`';
	}
    protected function queryReplace($sql)
    {
        // Произвести автозамену #!table# на primary_table
        $sql=str_replace("#!table#",$this->tbname(),$sql);
        // Произвести автозамену #!id# на idfield
        $sql=str_replace("#!id#",$this->tbname()
			.'.'
			.$this->idfield(),$sql);
        return $sql;
    }
    /**
     * Возвращаем id в виде объекта
     *  @param string $id - int, item_int, item_data
     */
	protected function id2obj($id)
	{
		// Возвращаем id в виде объекта
		$idobj = new sharpobj_data_item_int();
		
		if ($id instanceof sharpobj_data_item_int)
		{
			// Передан объект с целым числом
			$idobj = $id;
		}elseif ($id instanceof sharpobj_data_item_data)
		{
			// Передан объект с id
			$idobj->set('plain',$id->getId());
		}elseif (intval($id)>0)
		{
			// Передано целое число
			$idobj->set('plain',$id);
		}
		return $idobj;
	}
	
	/**
	 * sql-фрагмент LIMIT
	 */
	protected function sqlgenLimit($from=null,$limit=null)
	{
		if (is_null($from) AND is_null($limit))
		{
			return '';
		}elseif (is_null($from))
		{
			return 'LIMIT '.intval($limit);
		}else
		{
			return 'LIMIT '.intval($from).','.intval($limit);		
		}
	}	
	/**
	 * Возвращаем дамп для создания базы данных
	 * @return string (sql)
	 */
	function getDampDB()
	{
		//
		return '';
	}
}

/**
 * Формат объекта-хранилища
 * @author
 */
class sharpobj_storage_format
{
	protected $data_obj;
	protected $fields;
	protected $keys;
	protected $indexes;
	protected $comment='';
	function __construct()
	{
		// Создаем пустой объект data
		$this->data_obj = new sharpobj_data_item_data();
		$this->fields=array();
		$this->keys=array();
		$this->indexes=array();
	}
	function __clone()
	{
        $this->data_obj = clone $this->data_obj;
        $this->fields = clone $this->fields;
        $this->keys = clone $this->keys;
        $this->indexes = clone $this->indexes;
	}
	function setComment($comment)
	{
		$this->comment = $comment;
	}
	function getComment()
	{
		return $this->comment;
	}
	/**
	 * Добавить элемент (поле хранилища)	
	 * @param $datapath - путь к полю в sharpdata
	 * @param $colname - имя колонки в БД
	 * @param $type - тип поля в sharpdata
	 * @param $provider - имя провайдера (нужен, если хранилище поддерживает)
	 * @param $options - дополнительные опции
	 * @param $version - версия модуля, в котором это поле было добавлено (для update)
	 * @return bool
	 */
	function addItem($datapath,$colname,$type,$options=null,$version=0,$comment='')
	{
		if (is_null($datapath))
		{
			// Чтобы не указывать имя колонки дважды, когда оно совпадает с путем к переменной
			// если $datapath ===null считаем его совпадающим с колонкой
			$datapath = $colname;
		}
		// Добавляем информацию о формате
		$this->fields[$datapath] =
			array('datapath'=>$datapath,
					'colname'=>$colname,
					'type'=>$type,
					'options'=>$options,
					'version'=>$version,
					'comment'=>$comment
			);
		// Добавляем поле в образец контейнера
		return $this->data_obj->addItem($datapath,$type,$options);
	}
	/**
	 * Добавить индекс
	 */
	function addIndex($name,$type,$colnames,$version=0,$comment='')
	{
		//
		$this->indexes[]=array('name'=>$name,
								'type'=>$type,
								'colnames'=>$colnames,
								'comment'=>$comment,
								'version'=>$version);
	}
	/**
	 * Добавить ключ (может быть на нескольких колонках
	 */
	function addKey($name,$type,$colnames,$reftable=null,$refcolnames=null,$version=0,$comment='')
	{
		//
		mst_error('Добавление ключей не поддерживается',
					"Класс формата не поддерживает межтабличные ключи",1,true);
	}
	/**
	 * Возвращаем клон элемента	
	 * @param $datapath
	 * @return sharpobj_data_interface_item
	 */
	function getObj($datapath=null)
	{
		return clone $this->data_obj->cloneItem($datapath);
	}

	/**
	 * 	
	 * @param sharpobj_data_interface_item	$dataobj - объект с данными
	 * @param 								$provider - имя провайдера, поля которого необходимо отобразить
	 * @param 								$noempty - не выводить поля, которые пусты в dataobj
	 * @return array
	 */
	private function getPvtColsArray(sharpobj_data_interface_item $dataobj=null,$noempty=false)
	{
		// Получить массив с полями и именами колонок в базе
		$res = array();
		// Проверяем корректность набора параметров
		if ($noempty AND !is_object($dataobj))
		{	
			// Ошибка
			mst_error('Неправильный набор параметров',"Для обработки флага noempty необходимо передать ссылку на объект с данными",2);
		}
		foreach ($this->fields as $field)
		{
				if (is_object($dataobj) AND $noempty AND $dataobj->isEmpty($field['datapath']))
				{	// Текущее поле пусто и пустые поля отображать запрещено
					continue;
				}
				$res[($field['datapath'])]=$field['colname'];
		}
		return $res;
	}
	/**
	 * Получить имя поля, соответствующее колонке
	 */
	function getColName($datapath)
	{
	    return $this->fields[$datapath]['colname'];
	}
	/**
	 * Возвращает массив с именами колонок в ключах и типами - в значениях
	 *
	 * @return array
	 */
	function getColsTypesArray()
	{
		// Получить массив с полями и именами колонок в базе
		$res = array();
		foreach ($this->fields as $field)
		{
				$res[($field['colname'])]=$field;
		}
		return $res;
	}
	function getIndexesArray()
	{
		return $this->indexes;
	}
	function getColsArray(sharpobj_data_interface_item $dataobj=null, $noempty=false)
	{
		return $this->getPvtColsArray($dataobj, $noempty);
	}
	function getColNames(sharpobj_data_interface_item $dataobj=null, $quot = '`', $separator = ', ',$prefix='',$noempty=false)
	{
		$res = '';
		$fields = $this->getPvtColsArray($dataobj, $noempty);
		foreach ($fields as $field_datapath=>$field_colname)
		{
			// Собираем результирующую строку
			if (mb_strlen($res)>0)
			{
				// Если строка не пуста - добавляем разделитель
				$res .= $separator;
			}
			$res .= "{$prefix}{$quot}{$field_colname}{$quot}";
		}
		
		return $res;
	}
	function getColVals(sharpobj_data_interface_item $dataobj, $view, $quot = '`', 
			$separator = ', ',$noempty=false,$nullcode='NULL')
	{
		$res = '';
		$fields = $this->getPvtColsArray($dataobj, $noempty);
		foreach ($fields as $field_datapath=>$field_colname)
		{
			// Собираем результирующую строку
			if (mb_strlen($res)>0)
			{
				// Если строка не пуста - добавляем разделитель
				$res .= $separator;
			}
			// Получаем значение из контейнера
            if ($dataobj->isExists($field_datapath)===false)
            {
                mst_error('Неправильный формат переданного объекта',"Вложенный элемент ({$field_datapath}) не существует",2);
                $field_val = null;
            }else
            {
			    $field_val = $dataobj->get($view,$field_datapath);
            }
			if (is_null($field_val))
			{	// Если значение нулевое - присваиваем ему специальный код
				$field_val = $nullcode;
			}else
			{	// Иначе - заключаем в кавычки
				$field_val = $quot.$field_val.$quot;
			}
			$res .= $field_val;
		}

		return $res;
	}
	/**
	 * 	
	 * @param sharpobj_data_interface_item	$dataobj
	 * @param 								$view
	 * @param 								$provider
	 * @param 								$col_quot
	 * @param 								$col_prefix
	 * @param 								$val_quot
	 * @param 								$colval_separator
	 * @param 								$item_separator
	 * @param 								$noempty
	 * @param 								$nullcode
	 * @return string
	 */
	function getColNameVals(sharpobj_data_interface_item $dataobj, $view,
			$col_quot = '`', $col_prefix='',$val_quot = "'",
			$colval_separator = '=',$item_separator = ', ',
			$noempty=false,$nullcode='NULL')
	{
		$res = '';
		$fields = $this->getPvtColsArray($dataobj, $noempty);
		foreach ($fields as $field_datapath=>$field_colname)
		{
			// Собираем результирующую строку
			if (mb_strlen($res)>0)
			{
				// Если строка не пуста - добавляем разделитель
				$res .= $item_separator;
			}
			// Получаем значение из контейнера
			$field_val = $dataobj->get($view,$field_datapath);
			if (is_null($field_val))
			{	// Если значение нулевое - присваиваем ему специальный код
				$field_val = $nullcode;
			}else
			{	// Иначе - заключаем в кавычки
				$field_val = $val_quot.$field_val.$val_quot;
			}
			$res .= $col_prefix.$col_quot.$field_colname.$col_quot
				.$colval_separator.$field_val;
		}

		return $res;
	}
}

mst_modfileload($MT_mod_name,'libs/storage/simplemysql.php');
mst_modfileload($MT_mod_name,'libs/storage/mysqlflex.php');
mst_modfileload($MT_mod_name,'libs/storage/adapter.php');
?>